import os
import uuid
import pandas as pd
import datetime
import zipfile
import shutil
from io import BytesIO
from flask import render_template, request, redirect, url_for, flash, current_app, send_file
from werkzeug.utils import secure_filename
from bson import ObjectId

from . import upload_exam_bp
from blueprints.admin.views import admin_required, exams_collection

# 允许上传的文件类型
ALLOWED_EXTENSIONS = {'csv', 'xlsx', 'xls', 'zip'}
ALLOWED_IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

# 上传文件夹路径
UPLOAD_FOLDER = os.path.join('static', 'uploads', 'exam_templates')
QUESTION_IMAGE_FOLDER = os.path.join('static', 'uploads', 'questions')

def allowed_file(filename, allowed_extensions=ALLOWED_EXTENSIONS):
    """检查文件扩展名是否被允许"""
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions

def allowed_image_file(filename):
    """检查图片文件扩展名是否被允许"""
    return allowed_file(filename, ALLOWED_IMAGE_EXTENSIONS)

@upload_exam_bp.route('/', methods=['GET', 'POST'])
@admin_required
def upload_exam():
    if request.method == 'POST':
        # 检查是否有文件
        if 'exam_file' not in request.files:
            flash('没有选择文件', 'danger')
            return redirect(request.url)
        
        file = request.files['exam_file']
        
        # 如果用户没有选择文件
        if file.filename == '':
            flash('没有选择文件', 'danger')
            return redirect(request.url)
        
        if file and allowed_file(file.filename):
            try:
                # 解析文件
                ext = file.filename.rsplit('.', 1)[1].lower()
                
                # 临时文件存储
                temp_dir = None
                image_files = {}
                
                # 如果是ZIP文件，解压并提取Excel和图片
                if ext == 'zip':
                    # 创建临时目录
                    temp_dir = os.path.join(UPLOAD_FOLDER, 'temp_' + str(uuid.uuid4()))
                    os.makedirs(temp_dir, exist_ok=True)
                    
                    # 保存并解压ZIP文件
                    zip_path = os.path.join(temp_dir, secure_filename(file.filename))
                    file.save(zip_path)
                    
                    with zipfile.ZipFile(zip_path, 'r') as zip_ref:
                        zip_ref.extractall(temp_dir)
                    
                    # 查找Excel文件
                    excel_file = None
                    for root, _, files in os.walk(temp_dir):
                        for f in files:
                            if f.endswith(('.xlsx', '.xls', '.csv')):
                                excel_file = os.path.join(root, f)
                                break
                        if excel_file:
                            break
                    
                    if not excel_file:
                        if temp_dir and os.path.exists(temp_dir):
                            shutil.rmtree(temp_dir)
                        flash('ZIP文件中没有找到Excel或CSV文件', 'danger')
                        return redirect(request.url)
                    
                    # 收集所有图片文件
                    for root, _, files in os.walk(temp_dir):
                        for f in files:
                            if allowed_image_file(f):
                                image_files[f] = os.path.join(root, f)
                    
                    # 读取Excel文件
                    if excel_file.endswith('.csv'):
                        df = pd.read_csv(excel_file, encoding='utf-8')
                    else:
                        df = pd.read_excel(excel_file)
                
                else:  # 直接处理Excel或CSV
                    if ext == 'csv':
                        df = pd.read_csv(file, encoding='utf-8')
                    else:  # xlsx 或 xls
                        df = pd.read_excel(file)
                
                # 验证文件格式，至少需要有题目和答案列
                required_columns = ['题目类型', '题目内容', '选项', '正确答案', '科目', '试卷名称']
                missing_columns = [col for col in required_columns if col not in df.columns]
                
                if missing_columns:
                    if temp_dir and os.path.exists(temp_dir):
                        shutil.rmtree(temp_dir)
                    flash(f'文件格式错误，缺少必要的列: {", ".join(missing_columns)}', 'danger')
                    return redirect(request.url)
                
                # 获取试卷基本信息（假设每个试卷的信息在每行都相同）
                exam_name = df['试卷名称'].iloc[0]
                subject = df['科目'].iloc[0]
                difficulty = request.form.get('difficulty', '1')
                
                # 转换难度为整数
                try:
                    difficulty = int(difficulty)
                    if difficulty < 1 or difficulty > 5:
                        difficulty = 3  # 默认中等难度
                except ValueError:
                    difficulty = 3  # 默认中等难度
                
                # 验证基本信息
                if not exam_name or not subject:
                    if temp_dir and os.path.exists(temp_dir):
                        shutil.rmtree(temp_dir)
                    flash('试卷名称和科目不能为空！', 'danger')
                    return redirect(request.url)
                
                # 处理试题数据
                questions = []
                
                for idx, row in df.iterrows():
                    question_type = row['题目类型'].lower()
                    title = row['题目内容']
                    
                    # 验证题目类型
                    if question_type not in ['single', 'multiple', 'boolean']:
                        if temp_dir and os.path.exists(temp_dir):
                            shutil.rmtree(temp_dir)
                        flash(f'不支持的题目类型: {question_type}。支持的类型: single(单选题), multiple(多选题), boolean(判断题)', 'danger')
                        return redirect(request.url)
                    
                    # 验证题目内容
                    if not title:
                        if temp_dir and os.path.exists(temp_dir):
                            shutil.rmtree(temp_dir)
                        flash('题目内容不能为空！', 'danger')
                        return redirect(request.url)
                    
                    # 初始化题目对象
                    question = {
                        'type': question_type,
                        'title': title,
                        'has_image': False,
                        'image_path': None
                    }
                    
                    # 处理图片
                    if '图片文件名' in df.columns and not pd.isna(row['图片文件名']) and row['图片文件名']:
                        image_filename = str(row['图片文件名']).strip()
                        if image_filename in image_files:
                            # 确保上传目录存在
                            os.makedirs(QUESTION_IMAGE_FOLDER, exist_ok=True)
                            
                            # 使用UUID生成唯一文件名
                            unique_filename = f"{uuid.uuid4()}_{secure_filename(image_filename)}"
                            target_path = os.path.join(QUESTION_IMAGE_FOLDER, unique_filename)
                            
                            # 复制图片到目标目录
                            shutil.copy2(image_files[image_filename], target_path)
                            
                            # 更新题目信息
                            question['has_image'] = True
                            question['image_path'] = f"/{target_path.replace(os.sep, '/')}"
                    
                    if question_type in ['single', 'multiple']:
                        # 解析选项
                        options_str = row['选项']
                        if pd.isna(options_str) or not options_str.strip():
                            if temp_dir and os.path.exists(temp_dir):
                                shutil.rmtree(temp_dir)
                            flash(f'题目: "{title}" 的选项不能为空！', 'danger')
                            return redirect(request.url)
                        
                        # 选项格式可以是以分号分隔的字符串: "选项A;选项B;选项C;选项D"
                        options = [opt.strip() for opt in options_str.split(';') if opt.strip()]
                        
                        if len(options) < 2:
                            if temp_dir and os.path.exists(temp_dir):
                                shutil.rmtree(temp_dir)
                            flash(f'题目: "{title}" 至少需要两个选项！', 'danger')
                            return redirect(request.url)
                        
                        # 解析正确答案
                        correct_answers_str = str(row['正确答案'])
                        if pd.isna(correct_answers_str) or not correct_answers_str.strip():
                            if temp_dir and os.path.exists(temp_dir):
                                shutil.rmtree(temp_dir)
                            flash(f'题目: "{title}" 的正确答案不能为空！', 'danger')
                            return redirect(request.url)
                        
                        # 正确答案格式：
                        # - 单选题：一个数字，代表正确选项的索引（0开始）
                        # - 多选题：多个数字，用逗号分隔，代表正确选项的索引（0开始）
                        
                        correct_answers = []
                        
                        if question_type == 'single':
                            try:
                                correct_answer = int(correct_answers_str.strip())
                                if correct_answer < 0 or correct_answer >= len(options):
                                    if temp_dir and os.path.exists(temp_dir):
                                        shutil.rmtree(temp_dir)
                                    flash(f'题目: "{title}" 的正确答案索引超出范围！', 'danger')
                                    return redirect(request.url)
                                correct_answers = [correct_answer]
                            except ValueError:
                                if temp_dir and os.path.exists(temp_dir):
                                    shutil.rmtree(temp_dir)
                                flash(f'题目: "{title}" 的正确答案格式不正确，单选题答案应该是一个数字（0开始的索引）！', 'danger')
                                return redirect(request.url)
                        else:  # multiple
                            try:
                                for ans in correct_answers_str.split(','):
                                    ans = int(ans.strip())
                                    if ans < 0 or ans >= len(options):
                                        if temp_dir and os.path.exists(temp_dir):
                                            shutil.rmtree(temp_dir)
                                        flash(f'题目: "{title}" 的正确答案索引超出范围！', 'danger')
                                        return redirect(request.url)
                                    correct_answers.append(ans)
                                
                                if not correct_answers:
                                    if temp_dir and os.path.exists(temp_dir):
                                        shutil.rmtree(temp_dir)
                                    flash(f'题目: "{title}" 的多选题至少需要一个正确答案！', 'danger')
                                    return redirect(request.url)
                            except ValueError:
                                if temp_dir and os.path.exists(temp_dir):
                                    shutil.rmtree(temp_dir)
                                flash(f'题目: "{title}" 的正确答案格式不正确，多选题答案应该是以逗号分隔的数字（0开始的索引）！', 'danger')
                                return redirect(request.url)
                        
                        question['options'] = options
                        question['correct_answers'] = correct_answers
                    
                    else:  # boolean
                        # 解析布尔答案
                        correct_answer_str = str(row['正确答案']).strip().lower()
                        
                        if correct_answer_str in ['true', '1', 'yes', 'y', '是', '正确', 't']:
                            question['correct_answers'] = [True]
                        elif correct_answer_str in ['false', '0', 'no', 'n', '否', '错误', 'f']:
                            question['correct_answers'] = [False]
                        else:
                            if temp_dir and os.path.exists(temp_dir):
                                shutil.rmtree(temp_dir)
                            flash(f'题目: "{title}" 的判断题答案格式不正确，应该是表示True或False的值！', 'danger')
                            return redirect(request.url)
                    
                    questions.append(question)
                
                # 清理临时目录
                if temp_dir and os.path.exists(temp_dir):
                    shutil.rmtree(temp_dir)
                
                # 确保至少有一道题目
                if not questions:
                    flash('试卷至少需要一道题目！', 'danger')
                    return redirect(request.url)
                
                # 创建试卷
                exam = {
                    'name': exam_name,
                    'subject': subject,
                    'difficulty': difficulty,
                    'questions': questions,
                    'created_at': datetime.datetime.now().strftime('%Y-%m-%d %H:%M'),
                    'updated_at': datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
                }
                
                result = exams_collection.insert_one(exam)
                flash(f'成功上传试卷 "{exam_name}"，包含 {len(questions)} 道题目！', 'success')
                return redirect(url_for('admin.exam_list'))
                
            except Exception as e:
                if temp_dir and os.path.exists(temp_dir):
                    shutil.rmtree(temp_dir)
                flash(f'解析文件发生错误: {str(e)}', 'danger')
                return redirect(request.url)
        else:
            flash('不支持的文件格式，请上传 CSV、Excel 或 ZIP 文件', 'danger')
            return redirect(request.url)
    
    # GET请求
    return render_template('admin/upload_exam.html')

@upload_exam_bp.route('/download_template')
@admin_required
def download_template():
    """下载试卷上传模板"""
    # 创建示例数据
    data = {
        '题目类型': ['single', 'multiple', 'boolean', 'single'],
        '题目内容': [
            '以下哪个是Python的基本数据类型？',
            '以下哪些是Python的循环语句？',
            'Python中的列表是不可变的数据类型',
            '下图中展示的是哪种编程语言的logo？'
        ],
        '选项': [
            'String;Boolean;Loop;Datetime',
            'for;while;do-while;loop-until',
            '',
            'Python;Java;C++;JavaScript'
        ],
        '正确答案': [0, '0,1', 'False', 0],
        '科目': ['python', 'python', 'python', 'python'],
        '试卷名称': ['Python基础测试', 'Python基础测试', 'Python基础测试', 'Python基础测试'],
        '图片文件名': ['', '', '', 'python_logo.png']
    }
    
    df = pd.DataFrame(data)
    
    # 创建Excel文件
    output = BytesIO()
    writer = pd.ExcelWriter(output, engine='xlsxwriter')
    df.to_excel(writer, sheet_name='试卷模板', index=False)
    
    # 设置列宽
    worksheet = writer.sheets['试卷模板']
    worksheet.set_column('A:A', 12)  # 题目类型
    worksheet.set_column('B:B', 30)  # 题目内容
    worksheet.set_column('C:C', 25)  # 选项
    worksheet.set_column('D:D', 15)  # 正确答案
    worksheet.set_column('E:E', 10)  # 科目
    worksheet.set_column('F:F', 20)  # 试卷名称
    worksheet.set_column('G:G', 15)  # 图片文件名
    
    writer.close()
    output.seek(0)
    
    return send_file(
        output,
        mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        as_attachment=True,
        download_name='试卷上传模板.xlsx'
    )
